package com.hyt.it.ogt.ks.service.impl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.exception.NestedBusinessException;
import com.hyt.it.ogt.ks.api.kw.model.CandidateAccuracyDTO;
import com.hyt.it.ogt.ks.api.kw.model.CandidateScoreDTO;
import com.hyt.it.ogt.ks.config.KsBizRunTimeException;
import com.hyt.it.ogt.ks.enums.BizStatusCode;
import com.hyt.it.ogt.ks.enums.CandidateStatusCode;
import com.hyt.it.ogt.ks.enums.PaperItemTypeCode;
import com.hyt.it.ogt.ks.enums.PaperModeCode;
import com.hyt.it.ogt.ks.enums.PaperTypeCode;
import com.hyt.it.ogt.ks.feign.KwClient;
import com.hyt.it.ogt.ks.feign.PjClient;
import com.hyt.it.ogt.ks.feign.model.CandidatePaperInfo;
import com.hyt.it.ogt.ks.feign.model.Exam;
import com.hyt.it.ogt.ks.feign.model.ExamCandidate;
import com.hyt.it.ogt.ks.feign.model.ExamDTO;
import com.hyt.it.ogt.ks.feign.model.ItemDataVO;
import com.hyt.it.ogt.ks.feign.model.PaperDataVO;
import com.hyt.it.ogt.ks.mapper.ExamScoreMapper;
import com.hyt.it.ogt.ks.model.entity.CandidateAnswer;
import com.hyt.it.ogt.ks.model.entity.CandidateProcess;
import com.hyt.it.ogt.ks.model.entity.ExamScore;
import com.hyt.it.ogt.ks.model.vo.CandidateScoreVO;
import com.hyt.it.ogt.ks.model.vo.CandidateSubjectiveScoreVO;
import com.hyt.it.ogt.ks.model.vo.CandidateSubjectiveTotalScoreVO;
import com.hyt.it.ogt.ks.model.vo.ExamCandidateDetailInfoForScoreVO;
import com.hyt.it.ogt.ks.model.vo.ExamConfigVO;
import com.hyt.it.ogt.ks.model.vo.ExamPaperPackageVO;
import com.hyt.it.ogt.ks.model.vo.PaperSubjectiveScoreVO;
import com.hyt.it.ogt.ks.model.vo.ScoreItemDetailsVO;
import com.hyt.it.ogt.ks.model.vo.ScoreItemVO;
import com.hyt.it.ogt.ks.model.vo.ScorePaperDetailsVO;
import com.hyt.it.ogt.ks.model.vo.ScoreTopicDetailsVO;
import com.hyt.it.ogt.ks.model.vo.ScoreTotalVO;
import com.hyt.it.ogt.ks.model.vo.login.LoginInfo;
import com.hyt.it.ogt.ks.model.vo.login.ScoreLoginVO;
import com.hyt.it.ogt.ks.model.xyvo.XyPostExamScoreVO;
import com.hyt.it.ogt.ks.service.ExamInfoCacheService;
import com.hyt.it.ogt.ks.service.ICandidateAnswerBackupService;
import com.hyt.it.ogt.ks.service.ICandidateAnswerService;
import com.hyt.it.ogt.ks.service.ICandidateProcessService;
import com.hyt.it.ogt.ks.service.IExamCacheService;
import com.hyt.it.ogt.ks.service.IExamScoreService;
import com.hyt.it.ogt.ks.util.Constants;

import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author linjd
 * @since 2020-06-02
 */
@Slf4j
@Service
public class ExamScoreServiceImpl extends BaseServiceImpl<ExamScoreMapper, ExamScore> implements IExamScoreService {
    @Resource
    private ICandidateAnswerService iCandidateAnswerService;
    @Resource
    private ICandidateProcessService iCandidateProcessService;
    @Resource 
    private KwClient kwClient;
    @Resource 
    private PjClient pjClient;
	@Resource
	private IExamCacheService iExamCacheService;
	@Resource
	private ICandidateAnswerBackupService iCandidateAnswerBackupService;
	@Resource
	private ExamInfoCacheService examInfoCacheService;

    @Override
    public CandidateScoreDTO getScoreByExamCandidateId(String examCandidateId, String paperId, String paperVersion, Integer isBackup) {
		CandidateScoreDTO dto ;
		if(Objects.equals(0,isBackup)){
			dto = baseMapper.getScoreByExamCandidateId(examCandidateId, paperId, paperVersion);
		} else {
			dto = baseMapper.getScoreByExamCandidateIdWhenBackup(examCandidateId, paperId, paperVersion);
		}
        return dto;
    }

	@Override
	public ScoreLoginVO scoreLogin(String examId, String code, String loginType) {
		LambdaQueryWrapper<CandidateProcess> query = Wrappers.<CandidateProcess>lambdaQuery()
				.select(CandidateProcess::getCandidateId, CandidateProcess::getAdmissionNumber, CandidateProcess::getExamStatus)
				.eq(CandidateProcess::getExamId, examId).eq(CandidateProcess::getDelFlag, false);
		if("3".equals(loginType)){
			query.eq(CandidateProcess::getAdmissionNumber, code);
		} else {
			ApiResponse<LoginInfo> res = kwClient.getCandidateAdmissionNumber(examId, code, loginType);
			if (res.getCode().intValue() != BizStatusCode.KW_SUCCESS_OK.getCode().intValue()) {
				throw new KsBizRunTimeException(res.getCode());
			}
			query.eq(CandidateProcess::getAdmissionNumber, res.getData().getAdmissionNumber());
		}
		CandidateProcess candidateProcess = iCandidateProcessService.getOne(query);

		if(candidateProcess == null) {
			throw new KsBizRunTimeException(BizStatusCode.NOT_EXIST_ADMISSION_NUMBER.getCode());
		} else {
			ApiResponse<Boolean> res = kwClient.existCandidate(examId, candidateProcess.getAdmissionNumber());
			if(!res.getData()) {
				throw new KsBizRunTimeException(BizStatusCode.NOT_EXIST_ADMISSION_NUMBER.getCode());
			}
			if (candidateProcess.getExamStatus().intValue() < CandidateStatusCode.COMMIT.getCode().intValue()) {
				throw new KsBizRunTimeException(BizStatusCode.NOT_FINISH_EXAM.getCode());
			} else {
				ScoreLoginVO candidateScore = new ScoreLoginVO();
				candidateScore.setCandidateId(candidateProcess.getCandidateId());
				candidateScore.setState(candidateProcess.getExamStatus());
				candidateScore.setAdmissionNumber(candidateProcess.getAdmissionNumber());
				candidateScore.setExamId(examId);
				return candidateScore;
			}
		}
	}

	@Override
    public List<CandidateAccuracyDTO> getCandidateAccuracy(String examCandidateId) {
        return baseMapper.getCandidateAccuracy(examCandidateId);
    }
    
    @Override
    public CandidateScoreVO queryScore(String examId, String candidateId) {
    	CandidateScoreVO candidateScore = new CandidateScoreVO();
    	Boolean judgeScoreState = true;
    	QueryWrapper<CandidateProcess> queryCandidateProcess = Wrappers.query();
        queryCandidateProcess.lambda().select(CandidateProcess::getExamId, CandidateProcess::getAdmissionNumber,
						CandidateProcess::getCandidateId, CandidateProcess::getPaperId, CandidateProcess::getPaperVersion,
						CandidateProcess::getMaxScoreVer, CandidateProcess::getPaperMode, CandidateProcess::getRedoExamCount)
				.eq(CandidateProcess::getExamId, examId).eq(CandidateProcess::getCandidateId, candidateId);
        CandidateProcess candidateProcess = iCandidateProcessService.getOne(queryCandidateProcess);

        String kwCandidateStateRes = kwClient.getStateByAdmissionNumber(examId, candidateProcess.getAdmissionNumber());
        log.debug("调用考务系统获取考生状态信息：{}", kwCandidateStateRes);
        ApiResponse<ExamCandidate> kwCandidateStateResResponse = ApiResponse.ConvertRet(kwCandidateStateRes, ExamCandidate.class);
        if (kwCandidateStateResResponse.getCode().intValue() != BizStatusCode.KW_SUCCESS_OK.getCode().intValue() ||
			Objects.isNull(kwCandidateStateResResponse.getData())) {
            return null;
        }
		ExamCandidate examCandidate = kwCandidateStateResResponse.getData();
        Integer kwCandidateState = examCandidate.getState();
    	if (candidateProcess == null && kwCandidateState < CandidateStatusCode.COMMIT.getCode().intValue()) {
    		return null;
    	}

    	//获取考试内容
    	ExamDTO examDTO = examInfoCacheService.getExamInfoFromCache(examId);
	    log.debug("调用考务系统获取考试信息：{}", examDTO);
        if (Objects.isNull(examDTO)) {
            return null;
        }
        Exam exam = examDTO.getExam();
        LocalDateTime nowTime= LocalDateTime.now();
        if(exam.getBeginDate().isAfter(nowTime)) {
        	candidateScore.setExamState(0);
        } else if(exam.getEndDate().isBefore(nowTime)) {
        	candidateScore.setExamState(2);
        } else {
        	candidateScore.setExamState(1);
        }
        candidateScore.setState(kwCandidateState);
    	//获取考生配置信息
    	String kwCandidateInfos = kwClient.getCandidateInfos(examId, candidateProcess.getCandidateId());
    	log.debug("调用考务系统获取考生配置信息：{}", kwCandidateInfos);
    	@SuppressWarnings("unchecked")
    	ApiResponse<JSONArray> kwCandidateInfosResponse = JSON.parseObject(kwCandidateInfos, ApiResponse.class);
        if (kwCandidateInfosResponse.getCode().intValue() != BizStatusCode.KW_SUCCESS_OK.getCode().intValue()) {
            return null;
        }
		List<ExamCandidateDetailInfoForScoreVO> examCandidateDetailInfos = JSONObject.parseArray(kwCandidateInfosResponse.getData().toJSONString(), ExamCandidateDetailInfoForScoreVO.class);
        ExamCandidateDetailInfoForScoreVO examCandidateDetailInfo = new ExamCandidateDetailInfoForScoreVO();
        examCandidateDetailInfo.setFieldName("准考证号");
        examCandidateDetailInfo.setValue(candidateProcess.getAdmissionNumber());
        examCandidateDetailInfos.add(1, examCandidateDetailInfo);
        candidateScore.setCandiateInfo(examCandidateDetailInfos);
        if(kwCandidateState.intValue() == CandidateStatusCode.COMMIT.getCode().intValue()) {
	        ScoreTotalVO scoreTotal = new ScoreTotalVO();   
	        //获取考生得分	        
	        if(StringUtils.isBlank(candidateProcess.getPaperId()) || StringUtils.isBlank(candidateProcess.getPaperVersion())){
	            throw new NestedBusinessException("考生未开考");
	        }
			List<CandidateAnswer> candidateAnswers;
			QueryWrapper<CandidateAnswer> queryCandidateAnswer = Wrappers.query();
			queryCandidateAnswer.lambda().eq(CandidateAnswer::getExamId, examId)
					.eq(CandidateAnswer::getAdmissionNumber, candidateProcess.getAdmissionNumber())
					.eq(CandidateAnswer::getAnswerVer, candidateProcess.getMaxScoreVer());
			if(Objects.equals(0,examCandidate.getIsBackup())){
				candidateAnswers = iCandidateAnswerService.list(queryCandidateAnswer);
			} else {
				candidateAnswers = iCandidateAnswerBackupService.getAnswerList(examId, candidateProcess.getAdmissionNumber(), candidateProcess.getMaxScoreVer());
			}
	        //获取评卷数据
	        Boolean hasSubject = candidateAnswers.stream().filter(ca -> !ca.getObjectiveOrSubjective() && !ca.getItemType().equals(PaperItemTypeCode.ITEM_TYPE_COMPOUND_CODE.getCode())).count() > 0;
	        List<ScoreItemVO> scoreItems = new ArrayList<ScoreItemVO>();
	        
	        //获取试卷信息
	        if (PaperModeCode.MANY_PAPER.getCode().equals(candidateProcess.getPaperMode())) {	        	
	        	CandidateSubjectiveTotalScoreVO subjectiveScoreListFromPj = new CandidateSubjectiveTotalScoreVO();
		        if(hasSubject) {
		        	String subjectiveScoreJson = pjClient.getStudentSubjectScore(examId, candidateProcess.getAdmissionNumber());
		        	log.debug("调用评卷系统获取考生得分配置信息：{}", subjectiveScoreJson);
		        	
					ApiResponse<CandidateSubjectiveTotalScoreVO> subjectiveScoreResponse = ApiResponse.ConvertRet(subjectiveScoreJson, CandidateSubjectiveTotalScoreVO.class);
		        	if (subjectiveScoreResponse.getCode().intValue() == BizStatusCode.PJ_SUCCESS_CODE.getCode().intValue()) {
		        		subjectiveScoreListFromPj = subjectiveScoreResponse.getData();
						judgeScoreState = subjectiveScoreListFromPj.getMarkStatus();
		        	} else {
		        		judgeScoreState = false;
		        	}
		        }
	        	String resPaperList = kwClient.getPaperListByPaperIdVersoin(examId, candidateProcess.getPaperId(), candidateProcess.getPaperVersion());
	        	log.debug("调用考务系统通过试卷包Id、版本号获取试卷：{}", resPaperList);
	        	@SuppressWarnings("unchecked")
	        	ApiResponse<JSONArray> resPaperListResponse = JSON.parseObject(resPaperList, ApiResponse.class);
	            if (resPaperListResponse.getCode().intValue() != BizStatusCode.KW_SUCCESS_OK.getCode().intValue()) {
	                return null;
	            }
	            List<ExamPaperPackageVO> examPaperPackageList = JSONObject.parseArray(resPaperListResponse.getData().toJSONString(), ExamPaperPackageVO.class);
	            BigDecimal paperPackageScore = BigDecimal.ZERO;
	        	// BigDecimal userScore = BigDecimal.ZERO;
	            examPaperPackageList.sort(Comparator.comparing(ExamPaperPackageVO::getSort));
	            for (ExamPaperPackageVO examPaperPackage : examPaperPackageList) {
	        		PaperDataVO paperData = iExamCacheService.getPaperInfoCache(examPaperPackage.getPaperId(), examPaperPackage.getPaperVersion());
	        		if(PaperTypeCode.CHARACTER.getCode().equals(examPaperPackage.getPaperType())) {
	        			continue;
	        		}
	        		paperPackageScore = paperPackageScore.add(paperData.getPaperScore());
	        		ScoreItemVO scoreItem = new ScoreItemVO();
		        	scoreItem.setTopicScore(examPaperPackage.getPaperScore());
		        	scoreItem.setTopicName(examPaperPackage.getPaperName());
		        	scoreItem.setSort(examPaperPackage.getSort());
		        	
		        	List<PaperSubjectiveScoreVO> subjectiveScoreList = subjectiveScoreListFromPj.getPaperSubjectiveScores() == null 
		        			? new ArrayList<PaperSubjectiveScoreVO>() : subjectiveScoreListFromPj.getPaperSubjectiveScores();				      
		        		        	
		        	BigDecimal objectScore = candidateAnswers.stream()
		    							        			.filter(s -> examPaperPackage.getPaperId().equals(s.getPaperId()) && examPaperPackage.getPaperVersion().equals(s.getPaperVersion()) && s.getObjectiveOrSubjective())
		    								        			.map(ca ->ca.getScore() == null ? new BigDecimal(0) : ca.getScore())
		    								        			.reduce(BigDecimal.ZERO,BigDecimal::add);
		        	
		        	Optional<PaperSubjectiveScoreVO> paperSubjectiveScore = subjectiveScoreList.stream()
		        								.filter(s -> s.getPaperId().equals(examPaperPackage.getPaperId())
		        												&& s.getPaperVersion().toString().equals(examPaperPackage.getPaperVersion()))
		        								.findFirst();		        	
		        	BigDecimal subjectScore =  BigDecimal.ZERO;	  
		        	if (paperSubjectiveScore.isPresent()) {
		        		subjectScore = paperSubjectiveScore.get().getSubjectiveScore();
		        	}	    			
	    			BigDecimal userScore = 	scoreItem.getUserScore() == null ? BigDecimal.ZERO : scoreItem.getUserScore();				        			
	    			scoreItem.setUserScore(userScore.add(objectScore).add(subjectScore));
	    			scoreItems.add(scoreItem);
	        	}
	            scoreTotal.setScoreItem(scoreItems);   
	        	scoreTotal.setPaperScore(paperPackageScore);
	        	scoreTotal.setUserScore(scoreItems.stream().map(ScoreItemVO::getUserScore).reduce(BigDecimal.ZERO, BigDecimal::add));
				candidateScore.setCandidateScore(scoreTotal);
	        } else {
	        	List<CandidateSubjectiveScoreVO> subjectiveScoreListFromPj = new ArrayList<CandidateSubjectiveScoreVO>();
	 	        if(hasSubject) {
	 	        	String subjectiveScoreJson = pjClient.getStudentItemScore(examId, candidateProcess.getAdmissionNumber());
	 	        	log.debug("调用评卷系统获取考生得分配置信息：{}", subjectiveScoreJson);
	 	        	@SuppressWarnings("unchecked")
	 				ApiResponse<JSONArray> subjectiveScoreResponse = JSON.parseObject(subjectiveScoreJson, ApiResponse.class);
	 	        	if (subjectiveScoreResponse.getCode().intValue() == BizStatusCode.PJ_SUCCESS_CODE.getCode().intValue() && subjectiveScoreResponse.getData() != null) {
	 	        		subjectiveScoreListFromPj = JSONObject.parseArray(subjectiveScoreResponse.getData().toString(), CandidateSubjectiveScoreVO.class);
	 	        		if (subjectiveScoreListFromPj.size() == 0) {
							judgeScoreState = false;
						}
	 	        	} else {
	 	        		judgeScoreState = false;
	 	        	}
	 	        }
	        	PaperDataVO paperData = iExamCacheService.getPaperInfoCache(candidateProcess.getPaperId(), candidateProcess.getPaperVersion());
	    	    
	 	        scoreTotal.setPaperScore(paperData.getPaperScore());
	 	        List<CandidateSubjectiveScoreVO> subjectiveScoreList = subjectiveScoreListFromPj;
		        paperData.getTopicDataList().forEach(topicData -> {
		        	ScoreItemVO scoreItem = new ScoreItemVO();
		        	scoreItem.setTopicScore(topicData.getTopicScore());
		        	scoreItem.setTopicName(topicData.getTopicName());
		        	scoreItem.setSort(topicData.getTopicSort());
		        	List<String> itemIds = topicData.getItemDataList().stream().filter(i -> !i.getItemType().equals(PaperItemTypeCode.ITEM_TYPE_COMPOUND_CODE.getCode()))
		        											.map(i -> i.getItemId()).collect(Collectors.toList());
		        		        	
		        	BigDecimal objectScore = candidateAnswers.stream()
		    							        			.filter(s -> itemIds.contains(s.getItemId()) && s.getObjectiveOrSubjective())
		    								        			.map(ca ->ca.getScore() == null ? new BigDecimal(0) : ca.getScore())
		    								        			.reduce(BigDecimal.ZERO,BigDecimal::add);
		        	
		        	BigDecimal subjectScore = subjectiveScoreList.size() > 0 ? subjectiveScoreList.stream()
							.filter(ss -> itemIds.contains(ss.getItemId()))
							.map(ca ->ca.getScore() == null ? new BigDecimal(0) : ca.getScore())
		        			.reduce(BigDecimal.ZERO,BigDecimal::add) : BigDecimal.ZERO;	        	

	    		    scoreItem.setUserScore(objectScore.add(subjectScore));
	    								        			
	    			topicData.getItemDataList().forEach(itemData -> {
	    				if(itemData.getChildItemList().size() >0) {
	    					List<String> itemDataIds = itemData.getChildItemList().stream().map(i -> i.getItemId()).collect(Collectors.toList());
	    					BigDecimal objectItemDataScore = candidateAnswers.stream()
				        			.filter(s -> itemDataIds.contains(s.getItemId()) && s.getObjectiveOrSubjective())
					        			.map(ca ->ca.getScore() == null ? new BigDecimal(0) : ca.getScore())
					        			.reduce(BigDecimal.ZERO,BigDecimal::add);

    						BigDecimal subjectItemDataScore = subjectiveScoreList.size() > 0 ? subjectiveScoreList.stream()
									.filter(ss -> itemDataIds.contains(ss.getItemId()))
									.map(ca ->ca.getScore() == null ? new BigDecimal(0) : ca.getScore())
				        			.reduce(BigDecimal.ZERO,BigDecimal::add) : BigDecimal.ZERO;	 
				        	
				        			
				        	scoreItem.setUserScore(scoreItem.getUserScore().add(objectItemDataScore).add(subjectItemDataScore));
	    				}
	    			});	    								        			
	    			
		        	scoreItems.add(scoreItem);
		        });
		        scoreTotal.setUserScore(scoreItems.stream().map(ScoreItemVO::getUserScore).reduce(BigDecimal.ZERO, BigDecimal::add));
		        scoreTotal.setScoreItem(scoreItems);        
		        candidateScore.setCandidateScore(scoreTotal);
	        }
	        
	        //获取考试名称
	        CandidatePaperInfo candidatePaperInfo =
					iExamCacheService.getCandidatePaperInfoCache(candidateProcess.getExamId(),
							candidateProcess.getCandidateId());
	        candidateScore.setExamName(candidatePaperInfo.getExamName()); 
	        candidateScore.setJudgeScoreState(judgeScoreState);
        }
		//获取项目参数，练习模式用
		List<ExamConfigVO> examConfigVOList = iExamCacheService.getExamConfigCache(candidateProcess.getExamId());
		//是否保留最高分
		boolean keepHighestScore = examConfigVOList.stream().anyMatch(examConfigVO ->
				Constants.KEEP_HIGHEST_SCORE.equalsIgnoreCase(examConfigVO.getConfigCode()));
		candidateScore.setKeepHighestScore(keepHighestScore);
		candidateScore.setRedoExamCount(candidateProcess.getRedoExamCount());
		String kwCandidateCheatRes = kwClient.getCandidateCheatState(examId, candidateProcess.getAdmissionNumber());
        log.debug("调用考务系统获取考生作弊信息：{}", kwCandidateCheatRes);
        ApiResponse<Integer> kwCandidateCheatResResponse = ApiResponse.ConvertRet(kwCandidateCheatRes, Integer.class); 
        if (kwCandidateCheatResResponse.getCode().intValue() != BizStatusCode.KW_SUCCESS_OK.getCode().intValue()) {
            return null;
        }
        Integer kwCandidateCheat = kwCandidateCheatResResponse.getData();
        candidateScore.setCheatState(kwCandidateCheat);
		candidateScore.setCandidateId(candidateProcess.getCandidateId());
    	return candidateScore;
    }

    @Override
    public List<ScorePaperDetailsVO> queryScoreDetails(String examId, String candidateId) {
    	QueryWrapper<CandidateProcess> queryCandidateProcess = Wrappers.query();
		queryCandidateProcess.lambda().eq(CandidateProcess::getExamId, examId).eq(CandidateProcess::getCandidateId, candidateId);
		CandidateProcess candidateProcess = iCandidateProcessService.getOne(queryCandidateProcess);
		
		List<ScorePaperDetailsVO> scorePaperDetails = new ArrayList<ScorePaperDetailsVO>();
		
		List<CandidateAnswer> candidateAnswers = this.getCandidatePaperItemScore(examId, candidateProcess.getAdmissionNumber(), candidateProcess.getMaxScoreVer());
		Map<String, CandidateAnswer> candidateAnswerMap = candidateAnswers
				.stream().collect(Collectors.toMap(CandidateAnswer::getItemId , Function.identity()));
		Boolean hasSubject = candidateAnswers.stream().filter(ca -> !ca.getObjectiveOrSubjective()).count() > 0;
		List<CandidateSubjectiveScoreVO> subjectiveScoreListFromPj = new ArrayList<CandidateSubjectiveScoreVO>();
		
		if (hasSubject) {
        	String subjectiveScoreJson = pjClient.getStudentItemScore(examId, candidateProcess.getAdmissionNumber());
        	@SuppressWarnings("unchecked")
			ApiResponse<JSONArray> subjectiveScoreResponse = JSON.parseObject(subjectiveScoreJson, ApiResponse.class);
        	log.debug("调用评卷系统获取考生得分配置信息：{}", subjectiveScoreJson);
        	if (subjectiveScoreResponse.getCode().intValue() == BizStatusCode.PJ_SUCCESS_CODE.getCode().intValue()) {
        		subjectiveScoreListFromPj = JSONObject.parseArray(subjectiveScoreResponse.getData().toString(), CandidateSubjectiveScoreVO.class);
        	}
        }	
		List<CandidateSubjectiveScoreVO> subjectiveScoreList = subjectiveScoreListFromPj;
		//获取试卷信息
        if (PaperModeCode.MANY_PAPER.getCode().equals(candidateProcess.getPaperMode())) {
        	String resPaperList = kwClient.getPaperListByPaperIdVersoin(examId, candidateProcess.getPaperId(), candidateProcess.getPaperVersion());
        	log.debug("调用考务系统通过试卷包Id、版本号获取试卷：{}", resPaperList);
        	@SuppressWarnings("unchecked")
        	ApiResponse<JSONArray> resPaperListResponse = JSON.parseObject(resPaperList, ApiResponse.class);
            if (resPaperListResponse.getCode().intValue() != BizStatusCode.KW_SUCCESS_OK.getCode().intValue()) {
                return null;
            }
            List<ExamPaperPackageVO> examPaperPackageList = JSONObject.parseArray(resPaperListResponse.getData().toString(), ExamPaperPackageVO.class);
            examPaperPackageList.sort(Comparator.comparing(ExamPaperPackageVO::getSort));
            for (ExamPaperPackageVO examPaperPackage : examPaperPackageList) {
            	if(PaperTypeCode.CHARACTER.getCode().equals(examPaperPackage.getPaperType())) {
        			continue;
        		}
            	ScorePaperDetailsVO scorePaperDetail = new ScorePaperDetailsVO();
            	scorePaperDetail.setPaperName(examPaperPackage.getPaperName());
            	PaperDataVO paperData = iExamCacheService.getPaperInfoCache(examPaperPackage.getPaperId(), examPaperPackage.getPaperVersion());
            	List<ScoreTopicDetailsVO> scoreTopicDetails = new ArrayList<ScoreTopicDetailsVO>();
            	paperData.getTopicDataList().forEach(topic -> {
            		ScoreTopicDetailsVO scoreTopicDetail = new ScoreTopicDetailsVO();
            		scoreTopicDetail.setTopicSort(topic.getTopicSort());  
            		scoreTopicDetail.setTopicName(topic.getTopicName());
            		List<ScoreItemDetailsVO> scoreItemDetails = new ArrayList<ScoreItemDetailsVO>();
            		topic.getItemDataList().forEach(item -> {
            			CandidateAnswer candidateAnswer = candidateAnswerMap.get(item.getItemId());
            			if(candidateAnswer != null) {
        					ScoreItemDetailsVO scoreItemDetail = new ScoreItemDetailsVO();					
        	    			scoreItemDetail.setItemSort(candidateAnswer.getItemMixSort());
							if(PaperItemTypeCode.ITEM_TYPE_FILL_IN_BLANKS_CODE.getCode().equals(candidateAnswer.getItemType())
									|| PaperItemTypeCode.ITEM_TYPE_MATCHING_CODE.getCode().equals(candidateAnswer.getItemType())
									|| PaperItemTypeCode.ITEM_TYPE_CLOZE_FILL_IN_BLANKS_CODE.getCode().equals(candidateAnswer.getItemType())
									|| PaperItemTypeCode.ITEM_TYPE_COMPOUND_CODE.getCode().equals(candidateAnswer.getItemType())) {
								BigDecimal useScore = this.getCompoundScore(item, candidateAnswerMap, subjectiveScoreList);
								scoreItemDetail.setUserScore(useScore);
							} else if (candidateAnswer.getObjectiveOrSubjective()) {
								scoreItemDetail.setUserScore(candidateAnswer.getScore()==null ? BigDecimal.ZERO : candidateAnswer.getScore());
        	    			} else {
								Optional<CandidateSubjectiveScoreVO> subjectiveScore = subjectiveScoreList.stream()
										.filter(s -> s.getItemId().equals(candidateAnswer.getItemId())
												&& examPaperPackage.getPaperId().equals(s.getPaperId())
												&& examPaperPackage.getPaperVersion().toString().equals(s.getPaperVersion()))
										.findFirst();
								BigDecimal userScore = subjectiveScore.isPresent()
										? subjectiveScore.get().getScore() == null ? new BigDecimal("0") : subjectiveScore.get().getScore()
										: new BigDecimal("0");
								scoreItemDetail.setUserScore(userScore);
        	    			}        	    			
        	    			scoreItemDetails.add(scoreItemDetail);
            			}
            		});
            		scoreTopicDetail.setScoreItemDetails(scoreItemDetails.stream().sorted(Comparator.comparing(ScoreItemDetailsVO::getItemSort)).collect(Collectors.toList()));
            		scoreTopicDetails.add(scoreTopicDetail);
            	});            
                scorePaperDetail.setScoreTopicDetails(scoreTopicDetails);
            	scorePaperDetails.add(scorePaperDetail);
            }            
        } else {
        	ScorePaperDetailsVO scorePaperDetail = new ScorePaperDetailsVO();
        	List<ScoreTopicDetailsVO> scoreTopicDetails = new ArrayList<ScoreTopicDetailsVO>();
            //获取试卷信息
            PaperDataVO paperData = iExamCacheService.getPaperInfoCache(candidateProcess.getPaperId(), candidateProcess.getPaperVersion());
            scorePaperDetail.setPaperName(paperData.getPaperName());
            paperData.getTopicDataList().forEach(topic -> {
        		ScoreTopicDetailsVO scoreTopicDetail = new ScoreTopicDetailsVO();
        		scoreTopicDetail.setTopicSort(topic.getTopicSort());  
        		scoreTopicDetail.setTopicName(topic.getTopicName());
        		List<ScoreItemDetailsVO> scoreItemDetails = new ArrayList<ScoreItemDetailsVO>();
        		topic.getItemDataList().forEach(item -> {
        			CandidateAnswer candidateAnswer = candidateAnswerMap.get(item.getItemId());
        			if(candidateAnswer != null) {
    					ScoreItemDetailsVO scoreItemDetail = new ScoreItemDetailsVO();					
    	    			scoreItemDetail.setItemSort(candidateAnswer.getItemMixSort());
    	    			if (candidateAnswer.getObjectiveOrSubjective()
								&& !(PaperItemTypeCode.ITEM_TYPE_CLOZE_FILL_IN_BLANKS_CODE.getCode().equals(candidateAnswer.getItemType())
								|| PaperItemTypeCode.ITEM_TYPE_MATCHING_CODE.getCode().equals(candidateAnswer.getItemType()))) {
    	    				scoreItemDetail.setUserScore(candidateAnswer.getScore());
    	    			} else {
    	    				if(PaperItemTypeCode.ITEM_TYPE_COMPOUND_CODE.getCode().equals(candidateAnswer.getItemType())
									|| PaperItemTypeCode.ITEM_TYPE_CLOZE_FILL_IN_BLANKS_CODE.getCode().equals(candidateAnswer.getItemType())
									|| PaperItemTypeCode.ITEM_TYPE_MATCHING_CODE.getCode().equals(candidateAnswer.getItemType())) {
    	    					BigDecimal useScore = this.getCompoundScore(item, candidateAnswerMap, subjectiveScoreList);    	    			
    	    					scoreItemDetail.setUserScore(useScore);
    	    				} else {
	    	    				Optional<CandidateSubjectiveScoreVO> subjectiveScore = subjectiveScoreList.stream().filter(s -> s.getItemId().equals(candidateAnswer.getItemId())).findFirst();
	    	    				BigDecimal userScore = subjectiveScore.isPresent() 
	    	    								? subjectiveScore.get().getScore() == null ? new BigDecimal("0") : subjectiveScore.get().getScore() 
	    	    								: new BigDecimal("0");
	    	    				scoreItemDetail.setUserScore(userScore);
    	    				}
    	    			}
    	    			
    	    			scoreItemDetails.add(scoreItemDetail);
        			}
        		});
        		scoreTopicDetail.setScoreItemDetails(scoreItemDetails.stream().sorted(Comparator.comparing(ScoreItemDetailsVO::getItemSort)).collect(Collectors.toList()));
        		scoreTopicDetails.add(scoreTopicDetail);
        	});            
            scorePaperDetail.setScoreTopicDetails(scoreTopicDetails);
            scorePaperDetails.add(scorePaperDetail);
        }
    	return scorePaperDetails;
    }
    
    private BigDecimal getCompoundScore(ItemDataVO item, Map<String, 
    								CandidateAnswer> candidateAnswerMap,
    								List<CandidateSubjectiveScoreVO> subjectiveScoreList) {
    	List<BigDecimal> userScoreList = new ArrayList<BigDecimal>();
		item.getChildItemList().forEach(childItem -> {
			CandidateAnswer candidateChildAnswer = candidateAnswerMap.get(childItem.getItemId());
			if (candidateChildAnswer != null) {
				if (candidateChildAnswer.getObjectiveOrSubjective()) {
					userScoreList.add(candidateChildAnswer.getScore() == null ? BigDecimal.ZERO : candidateChildAnswer.getScore());
				} else {
					Optional<CandidateSubjectiveScoreVO> subjectiveScore = subjectiveScoreList.stream()
							.filter(s -> s.getItemId().equals(candidateChildAnswer.getItemId())
									&& candidateChildAnswer.getPaperId().equals(s.getPaperId())
									&& candidateChildAnswer.getPaperVersion().equals(s.getPaperVersion()))
							.findFirst();
					userScoreList.add(subjectiveScore.isPresent() 
    								? subjectiveScore.get().getScore() == null ? new BigDecimal("0") : subjectiveScore.get().getScore() 
    								: new BigDecimal("0"));	        	        	    				
				}    
			}    	    						
		});
		return userScoreList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    public List<CandidateAnswer> getCandidatePaperItemScore(String examId, String admissionNumber,Integer answerVer){
		//判断是否已备份
		List<CandidateAnswer> dataList = new ArrayList<>();
		String kwCandidateStateRes = kwClient.getStateByAdmissionNumber(examId, admissionNumber);
		log.debug("调用考务系统获取考生状态信息：{}", kwCandidateStateRes);
		ApiResponse<ExamCandidate> kwCandidateStateResResponse = ApiResponse.ConvertRet(kwCandidateStateRes, ExamCandidate.class);
		if (kwCandidateStateResResponse.getCode().intValue() != BizStatusCode.KW_SUCCESS_OK.getCode().intValue()) {
			return dataList;
		}
		ExamCandidate examCandidate = kwCandidateStateResResponse.getData();
		if(Objects.equals(1,examCandidate.getIsBackup())){
			dataList = iCandidateAnswerBackupService.getAnswerList(examId,admissionNumber,answerVer);
		} else {
			LambdaQueryWrapper<CandidateAnswer> query = Wrappers.lambdaQuery();
			query.eq(CandidateAnswer::getExamId, examId)
					.eq(CandidateAnswer::getAnswerVer, answerVer)
					.eq(CandidateAnswer::getAdmissionNumber, admissionNumber);
			dataList = iCandidateAnswerService.list(query);
		}
/*
		Map<String, BigDecimal> map = new HashMap<>();
		// 特殊处理存在父小题号的小题，比如填空题
		List<CandidateAnswer> candidateAnswers = new ArrayList<>();
		dataList.stream().forEach(item -> {
			BigDecimal score = item.getScore() == null ? BigDecimal.ZERO : item.getScore();
			if(StringUtils.isBlank(item.getParentItemId())){
				candidateAnswers.add(item);
			}else{
				if(map.containsKey(item.getParentItemId())){
					score.add(map.get(item.getParentItemId()));
				}
				map.put(item.getParentItemId(), score);
			}
		});
		candidateAnswers.stream().forEach(item -> {
			if(PaperItemTypeCode.ITEM_TYPE_FILL_IN_BLANKS_CODE.getCode().equalsIgnoreCase(item.getItemType())){
				item.setScore(map.get(item.getItemId()));
			}
		});
		*/
		return dataList;
	}
    
    @Override
    public CandidateScoreVO queryXyScore(String admissionNumber) {
    	CandidateScoreVO candidateScore = new CandidateScoreVO();
    	List<XyPostExamScoreVO> scoreList = baseMapper.getXyPostExamScore(admissionNumber);
    	if (scoreList == null || scoreList.size() == 0) {
    		return null;
    	}
    	candidateScore.setCandidateId(admissionNumber);
    	candidateScore.setCheatState(0);
    	candidateScore.setExamName("兴业银行岗位考试");
    	candidateScore.setExamState(3);
    	candidateScore.setJudgeScoreState(true);
    	candidateScore.setKeepHighestScore(false);
    	candidateScore.setRedoExamCount(0);
    	candidateScore.setState(30);    	
    	List<ExamCandidateDetailInfoForScoreVO> candidateInfoList = new ArrayList<ExamCandidateDetailInfoForScoreVO>();
    	ExamCandidateDetailInfoForScoreVO candidateInfoName = new ExamCandidateDetailInfoForScoreVO();
    	candidateInfoName.setComponentName("input");
    	candidateInfoName.setFieldName("姓名");    	
    	candidateInfoName.setValue(scoreList.get(0).getName());
    	candidateInfoList.add(candidateInfoName);
    	
    	ExamCandidateDetailInfoForScoreVO candidateInfoAdmissionNumber = new ExamCandidateDetailInfoForScoreVO();
    	candidateInfoAdmissionNumber.setComponentName("input");
    	candidateInfoAdmissionNumber.setFieldName("身份证号");    	
    	candidateInfoAdmissionNumber.setValue(scoreList.get(0).getIdCard());
    	candidateInfoList.add(candidateInfoAdmissionNumber);    	
    	candidateScore.setCandiateInfo(candidateInfoList);
    	ScoreTotalVO scoreTotal = new ScoreTotalVO();
    	BigDecimal userScore = scoreList.stream().map(s -> s.getScore()).reduce(BigDecimal.ZERO, BigDecimal::add);
    	scoreTotal.setUserScore(userScore);
    	BigDecimal paperScore = (new BigDecimal(120)).multiply(new BigDecimal(scoreList.size()));
    	scoreTotal.setPaperScore(paperScore);
    	List<ScoreItemVO> scoreItems = new ArrayList<ScoreItemVO>();
    	Integer i = 1;
    	for (XyPostExamScoreVO score : scoreList) {
    		ScoreItemVO scoreItem = new ScoreItemVO();
    		scoreItem.setSort(i);
    		scoreItem.setTopicName(score.getSubject());
    		scoreItem.setTopicScore(new BigDecimal(120));
    		scoreItem.setUserScore(score.getScore());
    		scoreItems.add(scoreItem);
    		i++;
    	}
    	scoreTotal.setScoreItem(scoreItems);
    	candidateScore.setCandidateScore(scoreTotal);
    	return candidateScore;
    }
}
